
# 过程：生成和提交打印任务
# 确定生成概率：实例为每小时10个

 # 任意小时内，约10名学生在场，，每小时内每人会发起2次左右的打印，每次1-20页
 # 打印机的性能，若以草稿模式打印的话，每分钟10页， 若依正常模式打印的话，打印质量好，速度下降至每分钟5页
 
#  问题：怎样设定打印机的模式， 让所有人在不会等太久的前提下尽量提高打印的质量了

# 典型的决策支持问题， 但无法通过规则直接计算
# 问题如何抽象

# 对打印任务的问题建模

# 对象：打印任务、打印队列、打印机
# 任务的属性：提交时间、打印页数
# 队列的属性：具有FIFO性质的打印任务队列
# 打印机的属性：打印速度、是否繁忙
# 过程：生成和提交打印任务
# 确定生成概率，实例为每小时10个学生提交20个作业，概率为没180秒会有一个作业生成，概率为每秒1/180.
# 确定打印页数：实例是1-20页， 那么就是1-20页之间概率相同，随机生成一个页数

# 过程：实施打印
# 当前的打印作业：正在打印的作业
# 打印结束倒计时：新作业开始打印时开始倒计时，为0表示打印完毕，可以处理下一个作业

# 模式时间：
# 统一时间框架：以最小单位秒均匀流逝的时间，设定结束时间
# 同步所有过程：在一个时间单位里，对生成打印任务和实施打印两个过程各处理一次

# 创建打印队列对象
# 时间按照秒的单位流逝
# 按照概率生成打印作业，加入打印队列
# 如果打印机空闲，且队列不为空，则取出队首作业打印，并记录次作业等待时间
# 如果打印机忙，则按照打印速度进行1秒打印
# 如果当前作业打印完成，则打印机进入空闲
# 时间用尽，开始统计平均等待时间
# 作业的等待时间
# 生成作业时，记录生成的时间戳
# 开始打印时，当前时间减去生成时间即可

# 作业的打印时间
# 生成作业时， 记录作业的页数
# 开始打印时，页数除以打印速度即可

from pythonds.basic.queue import Queue
import random

class Printer():
    def __init__(self, ppm):
        self.pagerate = ppm  # 打印速度
        self.currentTask = None  # 打印任务
        self.timeRemaining = 0  # 任务倒计时
    
    def tick(self):
        # 
        if self.currentTask != None:
            self.timeRemaining = self.timeRemaining - 1
            if self.timeRemaining <= 0:
                self.currentTask = None
                # 4009281199
    
    def busy(self):
        if self.currentTask != None:
            return True
        else:
            return False
    
    def startNext(self, newtask):
        self.currentTask = newtask
        self.timeRemaining = newtask.getPages() * 60 / self.pagerate

class Task():
    def __init__(self, time):
        self.timestamp = time # 生成时间戳
        self.pages = random.randrange(1, 21) # 打印页数 随机
    
    def getStamp(self):
        return self.timestamp
    
    def getPages(self):
        return self.pages

    def waitTime(self, currenttime):
        return currenttime - self.timestamp # 等待时间
    
def newPrintTask():
    num = random.randrange(1, 181)  # 1/180概率生成作业
    if num == 180:
        return True
    else:
        return False

def siimulation(numseconds, pagesPerMinute): # 模拟

    labprinter = Printer(pagesPerMinute)
    printQueue = Queue()
    waitinttimes = []
    # 时间流逝
    for currensecond in range(numseconds):

        if newPrintTask():
            task = Task(currensecond)
            printQueue.enqueue(task)
        
        if (not labprinter.busy()) and (not printQueue.isEmpty()):
            nexttask = printQueue.dequeue()
            waitinttimes.append(nexttask.waitTime(currensecond))
            labprinter.startNext(nexttask)
        labprinter.tick()

    avgwait = sum(waitinttimes) / len(waitinttimes)
    print("Average Wait %6.2f secs %3d task2 remaining." % (avgwait, printQueue.size()))



if __name__ == "__main__":

    # 按照5ppm 、1小时的设定， 模拟运行10次
    for i in range(10):
        siimulation(3600, 5)
    print('*'*30)
    for i in range(10):
        siimulation(3600, 10)
    print('*'*30)
    
    # output:
    # Average Wait  88.84 secs   0 task2 remaining.
    # Average Wait  41.00 secs   0 task2 remaining.
    # Average Wait  38.58 secs   0 task2 remaining.
    # Average Wait  31.31 secs   0 task2 remaining.
    # Average Wait 115.00 secs   4 task2 remaining.
    # Average Wait 101.77 secs   0 task2 remaining.
    # Average Wait 107.93 secs   0 task2 remaining.
    # Average Wait  78.71 secs   0 task2 remaining.
    # Average Wait  94.44 secs   0 task2 remaining.
    # Average Wait  34.22 secs   0 task2 remaining.
    # ******************************
    # Average Wait   5.88 secs   0 task2 remaining.
    # Average Wait  24.04 secs   0 task2 remaining.
    # Average Wait  23.88 secs   0 task2 remaining.
    # Average Wait  14.54 secs   0 task2 remaining.
    # Average Wait   6.68 secs   0 task2 remaining.
    # Average Wait  11.50 secs   0 task2 remaining.
    # Average Wait  19.07 secs   0 task2 remaining.
    # Average Wait  31.11 secs   0 task2 remaining.
    # Average Wait  17.94 secs   1 task2 remaining.
    # Average Wait  17.00 secs   0 task2 remaining.
    # ******************************